/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <flgrCoreDataIO.h>
#include <flgrCoreVector.h>
#include <flgrCoreDispatch.h>
#include "flgrLinearGaussian.h"



/*!
 * \addtogroup group_fulguro_linear_kernel
 * @{
 */


///////////////////////////////////////////////////////////////////////////
// Macro for different type for flgr1d_set_gaussian_kernel_dtype function
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_SET_GAUSSIAN_KER_1D(dtype)			\
  FLGR_Vector *vec;						\
  fgFLOAT64 M;							\
  int v;							\
  fgFLOAT64 tmp,b,c,d;						\
								\
  FLGR_DECLARE_FUNCTION;					\
								\
  vec = flgr_vector_create(nhb->spp,nhb->type);			\
								\
  M = (fgFLOAT64) (nhb->length-1);				\
								\
  for(v=0 ; v<nhb->length ; v++) {				\
    b = pow((v-M/2),2);						\
    c = pow(sigma,2);						\
    d = b/c;							\
    tmp = exp(-0.5*d) * levelMax;				\
    flgr_vector_populate_from_scalar_##dtype(vec, (dtype) tmp);	\
    flgr1d_set_data_vector_##dtype(nhb,v,vec);			\
  }								\
								\
  flgr_vector_destroy(vec);					\
  return

void flgr1d_set_gaussian_kernel_fgBIT(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  flgr_no_define_type_function(FLGR_BIT);
}
void flgr1d_set_gaussian_kernel_fgUINT8(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_1D(fgUINT8);
}
void flgr1d_set_gaussian_kernel_fgUINT16(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_1D(fgUINT16);
}
void flgr1d_set_gaussian_kernel_fgUINT32(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_1D(fgUINT32);
}
void flgr1d_set_gaussian_kernel_fgINT8(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_1D(fgINT8);
}
void flgr1d_set_gaussian_kernel_fgINT16(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_1D(fgINT16);
}
void flgr1d_set_gaussian_kernel_fgINT32(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_1D(fgINT32);
}
void flgr1d_set_gaussian_kernel_fgFLOAT32(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_1D(fgFLOAT32);
}
void flgr1d_set_gaussian_kernel_fgFLOAT64(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_1D(fgFLOAT64);
}



//////////////////////////////////////////////////////////////////
/*! Create a Gaussian Kernel in a neighborhood definition
 *  @param nhb : a pointer to FLGR_Data1D
 *  @param sigma : a float value
 *  @param levelMax  : a float value
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_set_gaussian_kernel(FLGR_Data1D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_DECLARE_FUNCTION;

  if(nhb==NULL){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  FLGR_DISPATCH_PROCEDURE(nhb->type,flgr1d_set_gaussian_kernel,nhb, sigma, levelMax);
}













///////////////////////////////////////////////////////////////////////////
// Macro for different type for flgr2d_set_gaussian_kernel_dtype function
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_SET_GAUSSIAN_KER_2D(dtype)				\
  FLGR_Vector *vec;							\
  fgFLOAT64 N,M;							\
  int v,u;								\
  fgFLOAT64 tmp,a,b,c,d;						\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  vec = flgr_vector_create(nhb->spp,nhb->type);				\
									\
  N = (fgFLOAT64) (nhb->size_y-1);					\
  M = (fgFLOAT64) (nhb->size_x-1);					\
  									\
  for(u=0 ; u<nhb->size_y ; u++) {					\
    for(v=0 ; v<nhb->size_x ; v++) {					\
      a = pow((u-N/2),2);						\
      b = pow((v-M/2),2);						\
      c = pow(sigma,2);							\
      d =(a+b)/c;							\
      tmp = exp(-0.5*d) * levelMax;					\
      flgr_vector_populate_from_scalar_##dtype(vec, (dtype) tmp);	\
      flgr2d_set_data_vector_##dtype(nhb,u,v,vec);			\
    }									\
  }									\
									\
  flgr_vector_destroy(vec);						\
  return

void flgr2d_set_gaussian_kernel_fgBIT(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  flgr_no_define_type_function(FLGR_BIT);
}
void flgr2d_set_gaussian_kernel_fgUINT8(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_2D(fgUINT8);
}
void flgr2d_set_gaussian_kernel_fgUINT16(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_2D(fgUINT16);
}
void flgr2d_set_gaussian_kernel_fgUINT32(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_2D(fgUINT32);
}
void flgr2d_set_gaussian_kernel_fgINT8(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_2D(fgINT8);
}
void flgr2d_set_gaussian_kernel_fgINT16(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_2D(fgINT16);
}
void flgr2d_set_gaussian_kernel_fgINT32(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_2D(fgINT32);
}
void flgr2d_set_gaussian_kernel_fgFLOAT32(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_2D(fgFLOAT32);
}
void flgr2d_set_gaussian_kernel_fgFLOAT64(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_MACRO_SET_GAUSSIAN_KER_2D(fgFLOAT64);
}



//////////////////////////////////////////////////////////////////
/*! Create a Gaussian Kernel in a neighborhood definition
 *  @param nhb : a pointer to FLGR_Data2D
 *  @param sigma : a float value
 *  @param levelMax  : a float value
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_set_gaussian_kernel(FLGR_Data2D *nhb, fgFLOAT64 sigma, fgFLOAT64 levelMax) {
  FLGR_DECLARE_FUNCTION;

  if(nhb==NULL){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  FLGR_DISPATCH_PROCEDURE(nhb->type,flgr2d_set_gaussian_kernel,nhb, sigma, levelMax);
}





//!@}
